/**
 * ComboBox Component Main Class - Created by FlashFrameLess Team OCT/2008
 *
 * @author		FabioTNT / FlashFrameLessTeam - http://www.flashframeless.com/
 * @version		1.0
 */

package com.flashframeless.components.ui.combo {

	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.events.KeyboardEvent;
	import flash.ui.Keyboard;
	//
	import com.flashframeless.components.ui.combo.Item;
	import com.flashframeless.components.ui.scrollBar.ScrollBar;
	import com.flashframeless.components.ui.scrollBar.ScrollBarEvent;
	import com.flashframeless.math.NumberUtils;
	//
	import caurina.transitions.Tweener;
	
	public class ComboBox extends MovieClip {
		
		private var _handler	: MovieClip;
		private var _target		: Sprite 	= new Sprite();
		private var _mask		: MovieClip;
		private var _hitArea	: MovieClip;
		private var _arrItens	: Array		= new Array();
		private var _arrData	: Array		= new Array();
		private var _backGround	: MovieClip;
		private var _vBorder	: uint		= 0;
		private var _rowCount	: uint 		= 5;
		private var _borderArea	: uint		= 25;
		private var _data		: Object;
		private var _itemHeight : uint;
		private var _bgHeight 	: uint;
		private var _initMaskW	: uint;
		private var _scrollVel	: Number 	= .1;
		private var _textAlign	: String	= 'left';
		private var _scrollBar	: MovieClip;
		private var _booScroll	: Boolean	= true;
		private var _range		: Number;
		
		public function ComboBox():void {
			
			//
			setupInteractions();
			
			dispatchEvent( new Event( Event.COMPLETE ) );
			
		}
		
		private function setupInteractions():void {
			
			//Set Clip Vars
			_mask		= maskMc;
			_backGround = backGroundMc;
			_hitArea	= hitMc;
			_handler	= this['parent'];
			_scrollBar	= scrollMc;
			
			_hitArea.alpha 		= 0;
			_scrollBar.visible 	= false;
			
			_bgHeight 	= _backGround.height;
			_initMaskW 	= _mask.width;
			
			//Set Target Mask
			addChild( _target );			
			_target.mask 	= _mask;
			_target.visible = false;
			
			//Set Mask and Target( Alvo ) Position
			_mask.y = _target.y = _backGround.y + 1;
			_mask.x = _target.x = _backGround.x;			
			
			//Active Listeners
			//activeListeners();
			
			addEventListener( KeyboardEvent.KEY_UP, keyHandler );
			
		}
		
		/**
		 * Set target value, recive parameter by Item handler.
		 *
		 * @param	status	Boolean
		 * @return			void
		 */
		public function setValue( evt:MouseEvent ) {
			
			_data = evt.target['parent'].data;			
			
			dispatchEvent( new Event( Event.CHANGE ) );
			
			onClick();
			
		}
		
		/**
		 * Active/Desactive Listeners.
		 *
		 * @param	status	Boolean
		 * @return			void
		 */
		private function activeListeners( status:Boolean = true ):void{
			
			var method:String = status ? 'addEventListener' : 'removeEventListener';
			
			//init onOver Listener
			_hitArea[method]( MouseEvent.MOUSE_OVER, onOver );
			
			//init onOut Listener
			_hitArea[method]( MouseEvent.MOUSE_OUT, onOut );
			
			//init onClick Listener
			_hitArea[method]( MouseEvent.MOUSE_UP, onClick );
			
			_hitArea.buttonMode = status;
			
			onOut();
			
		}
		
		/**
		 * setWidth
		 * Set all itens width value.
		 *
		 * @param	maxWidth	uint
		 * @return				void
		 */
		private function setWidth( maxWidth:uint ) {
			
			var i:uint;
			
			for ( i = 0; i < _arrItens.length; i++ ) {
				
				_arrItens[i].setWidth( maxWidth );
				
			}			
			
		}
		
		/*-------------------------------------------------------------------------------------------------*\
		|* Handlers ---------------------------------------------------------------------------------------*|
		\*-------------------------------------------------------------------------------------------------*/
		
		/**
		 * OnOver Handler.
		 *
		 * @param	evt		MouseEvent
		 * @return			void
		 */
		private function onOver( evt:MouseEvent = null ):void {
			
			//Over
			dispatchEvent( new MouseEvent( MouseEvent.MOUSE_OVER ) );
			
		}
		
		/**
		 * OnOut Handler.
		 *
		 * @param	evt		MouseEvent
		 * @return			void
		 */
		private function onOut( evt:MouseEvent = null ):void {
			
			//Out
			dispatchEvent( new MouseEvent( MouseEvent.MOUSE_OUT ) );
			
		}
		
		/**
		 * OnClick Handler.
		 *
		 * @param	evt		MouseEvent
		 * @return			void
		 */
		private function onClick( evt:MouseEvent = null ):void {
			
			activeListeners( false );
			
			var alphaVal	: uint = int( !_target.visible );
			
			//Manage the Scroller Handler
			//this[ ( !_target.visible ? 'addEventListener' : 'removeEventListener' ) ]( KeyboardEvent.KEY_UP, keyHandler );
			this[ ( !_target.visible ? 'addEventListener' : 'removeEventListener' ) ]( Event.ENTER_FRAME, scroller );
			_scrollBar[ ( !_target.visible ? 'addEventListener' : 'removeEventListener' ) ]( ScrollBarEvent.UPDATE, barScroller );
			
			//-----Animation-----
			
			//Set Y position of Target
			var posY:int = Math.ceil( _mask.y + ( -_target.height * int( _target.visible ) ) );
			
			_scrollBar.scrollPercent = 0/*posY / _range*/;
			
			_scrollBar.visible = !_target.visible;
			
			//Apply the Tween in Target
			Tweener.addTween( _target, { y:posY, time:.1, transition:'easeOutExpo', onUpdate:function() {
				
				//Set height of BackGround
				_backGround.bordaMc.height = NumberUtils.setToRange( _target.height + _target.y + 1, _bgHeight, _backGround.bordaMc.height = _mask.height + 2 );
				
				_scrollBar.bgMc.height 	  = _mask.height;
				_scrollBar.trackMc.height = _mask.height + 2;
				
			}, onComplete:function() {
				
				_scrollBar.setLimits();
				
			} } );
			
			//Set Backgroud Width
			
			Tweener.addTween( _backGround.bordaMc, { 
				
				delay:	.2 * int( _target.visible ),
				x:		Math.min( _mask.x * int(!_target.visible), 0 ),
				width:	Math.max( _mask.width * int( !_target.visible ) + 1, _initMaskW ),
				time:	.2 * int( _target.visible ),
				
				onUpdate:function() {
					
					_backGround.bgMc.x 		= this.x + 1;
					_backGround.bgMc.width 	= this.width - 2;
					
				}				
				
			} );
			
			//Set Target visible propiety
			Tweener.addTween( this, { delay:.3*int( _target.visible ), onStart:function() {
				
				_target.visible = !_target.visible;
				
				activeListeners();
				
			} } );
			
			dispatchEvent( new Event( Event.CLOSE ) );
			
		}
		
		/**
		 * Key Handler.
		 *
		 * @param	evt		Event
		 * @return			void
		 */
		private function keyHandler( evt:KeyboardEvent ):void {
			
			var i		: uint;
			var posY	: Number;
			
			switch( evt.keyCode ) {
				
				case Keyboard.DOWN.valueOf():
					
					posY = _target.y - _itemHeight - 1;
					
					posY = NumberUtils.setToRange( posY, -_target.height + _mask.height + 1, 0, 'round' );
					
				break
				
				case Keyboard.UP.valueOf():
					
					posY = _target.y + _itemHeight + 1;
					
					posY = NumberUtils.setToRange( posY, -_target.height + _mask.height + 1, 0, 'round' );
					
				break
				
				default:
					
					for ( i = 0; i < _arrData.length; i++ ) {				
						
						if ( _arrData[i].label.charCodeAt( 0 ) == evt.keyCode ) {
							
							posY = -( _itemHeight * i );
							
							posY = NumberUtils.setToRange( posY, -_target.height + _mask.height + 1, 0, 'round' );
							
							break;
							
						}
						
					}			
					
				break
				
			}
			
			if ( posY ) {
				
				_scrollBar.scrollPercent = posY / _range;
				
				Tweener.addTween( _target, { y:posY } );
				
			}
			
		}
		
		/**
		 * MouseMove Handler.
		 *
		 * @param	evt		Event
		 * @return			void
		 */
		private function scroller( evt:Event ):void {
			
			if ( mouseX < -( _borderArea + _mask.width ) || mouseX > this.width + _borderArea || mouseY < -_borderArea || mouseY > _mask.height + _borderArea ) {
				
				onClick();
				
			}
			
			if ( !_booScroll ) {
				
				_target.y -= ( _mask.y + mouseY - _mask.height / 2 ) * _scrollVel;
				
				_target.y = NumberUtils.setToRange( _target.y, _range + 1, 0, 'round' );
				
			}
			
		}
		
		/**
		 * ScrollBar Handler.
		 *
		 * @param	evt		Event
		 * @return			void
		 */
		private function barScroller( evt:ScrollBarEvent ):void {
			
			_target.y = ( -_target.height + _mask.height + 2 ) * evt.scrollValue;
			
		}
		
		/*-------------------------------------------------------------------------------------------------*\
		|* Getters e Setters ------------------------------------------------------------------------------*|
		\*-------------------------------------------------------------------------------------------------*/
		
		/**
		 * DataProvider Setter.
		 *
		 * @param	arrData	Array
		 * @return			void
		 */
		public function set dataProvider( arrData:Array ) {
			
			var i:uint;
			var maxWidth:uint;
			
			_arrData = arrData;
			
			for ( i = 0; i < _arrItens.length; i++ ) {
				
				_target.removeChild( _arrItens[i] );
				
			}
			
			_arrItens = [];
			
			for ( i = 0; i < arrData.length; i++ ) {
				
				var clip:Item 	= new Item();
				
				clip.textAlign 	= _textAlign;
				
				clip.parameters = arrData[i];
				
				_itemHeight = clip.height;
				
				//Set item Position
				clip.y = ( _itemHeight + _vBorder ) * i;
				
				_target.addChild( clip );
				
				_arrItens.push( clip );
				
				maxWidth = Math.max( maxWidth, clip.width );
				
			}
			
			setWidth( maxWidth );
			
			_target.x = _mask.x	= - maxWidth + _initMaskW-1;
			_mask.width 		= maxWidth;
			_mask.height 		= ( clip.height + _vBorder ) * Math.min( _rowCount, arrData.length );
			
			_range = -_target.height + _mask.height;
			
			_target.y = _range;
			
			activeListeners();
			
		}
		
		/**
		 * Combo Enabled Setter.
		 *
		 * @param	status	Boolean
		 * @return			void
		 */
		 public function set comboEnabled( status:Boolean ) {
			
			//Active or Desactive Mouse Events
			activeListeners( status );
			
		}
		
		/**
		 * Text Align Setter.
		 *
		 * @param	align	String
		 * @return			void
		 */
		 public function set textAlign( align:String ) {
			
			//Set Text Align
			_textAlign = align.toLowerCase();
			
		}
		
		/**
		 * Data Getter.
		 *
		 * @return			String
		 */
		public function get data():Object {
			
			return _data;
			
		}
		
	}
}